package side_server;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Iterator;
import data_structure.Files;

public class ServerConnection implements Runnable
{
	private Socket 			socket;
	private String 			msg;
	private OutputStream	out;
	private InputStream  	in;
	private BufferedReader 	br;
	private BufferedWriter  bw;
	private Files			files;
	private int 			prog = 0;
	private boolean			running=true;
	
	@Override
	public void run() {
		try {
			doTalk();
		} catch (SocketException e) {
			System.out.println("SOCKET INVALIDO");
		} catch (IOException e) {
			System.out.println("ERRORE I/O");
		}
	}
	
	public ServerConnection(Socket socket, String msg)
	{
		this.socket=socket;
		this.msg=msg.toUpperCase();
	}
	
	private void doTalk() throws IOException,SocketException
	{
		out=socket.getOutputStream();
		in=socket.getInputStream();
		br = new BufferedReader(new InputStreamReader(in));
		bw = new BufferedWriter(new OutputStreamWriter(out));
		
		while (running)
		{	
			if(msg.equals("SHARE"))
				share(true);
			else if(msg.equals("WAIT"))
				waitForResponse();
			else if(msg.equals("LISTPEERS"))
				listPeers(false);
			else if(msg.equals("GETPEERS"))
				listPeers(true);
			else if(msg.equals("SEND"))
				send();	
			else if(msg.equals("CANSHARE"))
				canShare();
			else if(msg.equals("LEAVE"))
				leave();
			else if(msg.equals("JOIN"))
				join();
			//else if(msg.equals("SHAREPEERS"))
			//	receivePeers();
			else if(msg.contains("REMOVE:"))
				removePeers();
		}
		socket.close();
	}
	
	public void newMessage(String msg)
	{
		this.msg=msg.toUpperCase();
	}
	
	private void listPeers(boolean next) throws IOException
	{
		String listPeers;
		listPeers = "\n\n" + Server.getInstance().getPeerList() + "\n";
		bw.write(listPeers);
		bw.flush();
		if(br.readLine().toUpperCase().equals("OK"))
		{
			running=next;
		}
	}
	
	private void waitForResponse() throws IOException
	{
		prog++;
		bw.write("WAIT FOR MESSAGE\n");
		bw.flush();
		msg = br.readLine().toUpperCase();
		System.out.println(prog + ") MESSAGE RECEIVED: " + msg);
		running = true;
	}
	
	private void send() throws IOException,SocketException
	{
		bw.write("READY\n"); //INVIO READY PER INIZIARE IL TRASFERIMENTO
		bw.flush(); 
		
		String listPeers = br.readLine(); //RICEVO LA LISTA DI PEERS
		String[] list = listPeers.split(Server.SEP);
		for(int k=0;k<list.length;k++)
		{
			if (!Server.getInstance().getPeerSet().contains(list[k]))
			{	//AGGIUNGO IL PEER ALLA LISTA
				System.out.println("ADDING PEER: " + list[k]);
				Server.getInstance().getPeerSet().add(list[k]);
			}
		}
		
		bw.write("OK");
		bw.flush();
	}
	
	private void canShare() throws IOException{
		//Creo la stringa di peers da inviare
		String myPeers=Server.getInstance().getPeerList();
		
		bw.write(myPeers + "\n");
		bw.flush();
		
		//Ricevo i peers da aggiungere
		myPeers=br.readLine();
		
		String[] splitPeers = myPeers.split(Server.SEP);
		for(int i=0;i<splitPeers.length;i++)
		{
			Server.getInstance().getPeerSet().add(splitPeers[i]);
		}
		//Grazie per tutto il pesce...
		bw.write("DONE\n");
		bw.flush();
	}
	
	private void leave() throws IOException
	{
		String removePeer;
		bw.write("WHAT\n");
		bw.flush();
		removePeer = br.readLine();
		Server.getInstance().getSocket(removePeer).close();
		Server.getInstance().getSockets().remove(removePeer);
		Server.getInstance().getPeerSet().remove(removePeer);
		bw.write("OK");
		bw.flush();
	}
	
	private void join() throws IOException
	{
		bw.write("WHO\n");
		bw.flush();
		String address = br.readLine();
		String[] split = address.split(" ");
		Socket socket = new Socket(split[0], Integer.parseInt(split[1]));
		Server.getInstance().getPeerSet().add(address);
		Server.getInstance().addSocket(address, socket);
		prog ++;
		System.out.println(prog + ") JOIN TO PEER " + address);
		bw.write("OK\n");
		bw.flush();
		running=true;
		sharePeers(socket);
		running=false;
	}
	
	private void sharePeers(Socket socket) throws UnknownHostException, IOException
	{	//LATO SERVER
		OutputStream out=socket.getOutputStream();
		InputStream in=socket.getInputStream();
		BufferedReader br = new BufferedReader(new InputStreamReader(in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
		
		String response =  br.readLine();
		prog++;
		System.out.println("SHARE PEERS (" + response + ")");
		bw.write("SHARE\n");
		bw.flush();
		response =  br.readLine();
		System.out.println("RESPONSE: " + response);
		prog++;
		String elenco = Server.getInstance().getPeerList();
		System.out.println("SENDING PEERLIST");
		System.out.println(elenco);
		bw.write(elenco + "\n");
		bw.flush();
		System.out.println("RESPONSE: " + br.readLine());
		prog++;
		System.out.println("OPERATION COMPLETED");
		socket.close();
	}
	
	private void share(boolean run) throws IOException
	{	//LATO CLIENT
		prog++;
		System.out.println("WAITING FOR PEERLIST");
		bw.write("READY\n");
		bw.flush();
		//Ricevo l'elenco
		String[] peers = br.readLine().split(Server.SEP);
		prog++;
		System.out.println("PEERLIST RECEIVED");
		for(int i=0;i<peers.length;i++)
		{
			String[] thePeer = peers[i].split(" ");  
			Socket socket = new Socket(thePeer[0], Integer.parseInt(thePeer[1]));
			if(!Server.getInstance().getPeerSet().contains(peers[i]))
			{
				Server.getInstance().getPeerSet().add(peers[i]);
				Server.getInstance().getSockets().put(peers[i], socket);
			}
		}
		prog++;
		System.out.println("NEW PEERLIST:");
		System.out.println(Server.getInstance().getPeerList());
		bw.write("OK\n");
		bw.flush();
	}
	
	private void receivePeers() throws IOException
	{
		String[] peers =  br.readLine().split(Server.SEP);
		System.out.println("RECEIVED THOSE PEERS:");
		for (int i=0;i<peers.length;i++)
		{
			System.out.println(peers[i]);
		}
	}
	
	private void removePeers() throws IOException
	{
		msg = msg.replace("REMOVE:", "");
		Server.getInstance().getSocket(msg).close();
		Server.getInstance().removeSocket(msg);
		Server.getInstance().getAddressSet().remove(msg);
	}
	
}
